﻿#pragma once

#include "Core/Camera.h"
#include "Core/Input.h"
#include "World/BlockData.h"
#include "World/WorldRayCast.h"
#include "World/Direction.h"
#include "Physics/AABB.h"

class CORE_API Player
{
public:
  Player(const Ref<World> &world, const Ref<Persistence> &persistence);
  ~Player();

  glm::vec3 GetForward() const;
  glm::vec3 GetUp() const;
  glm::vec3 GetRight() const;

  void SetCamera(Ref<Camera> camera) { m_camera = camera; }
  Ref<Camera> GetCamera() const { return m_camera; }

  void SetPosition(const glm::vec3 &position);
  void SetRotation(const glm::vec3 &rotation);
  glm::vec3 GetPosition() const;
  glm::vec3 GetRotation() const;

  Direction GetDirection() const { return m_direction; }

  void EnableMouseCursor(bool enable);
  void ToggleMouseCursor();

  void Update(float deltaTime);

  bool HasRayCastHit() const { return m_hasHit; }
  HitTarget &GetHitTarget() { return m_hitTarget; }

  void SetRunning(bool running) { m_isRunning = running; }
  bool IsRunning() const { return m_isRunning; }

  void TryJump(bool force = false);

  float GetSpeed() const;
  float GetJumpSpeed() const;

  float walkingSpeedMultiplier = 1.0f;
  float runningSpeedMultiplier = 1.6f;
  float inSkyHorizontalSpeedMultiplier = 0.2f;
  float jumpSpeedMultiplier = 1.0f;
  float rotatingSpeed = 85.0f;
  float mouseSensitivity = 0.2f;
  float gravityConstant = 27.12f;
  float reach = 6.5f;
  bool autoJump = true;

  static constexpr AABB PlayerAABB = AABB{
      {-0.3, -1.5, -0.3},
      {0.3, 0.3, 0.3},
  };

  static constexpr std::array<glm::vec3, 8> PlayerBoundingBox = {{
      {0.3, 0.3, 0.3},
      {0.3, 0.3, -0.3},
      {-0.3, 0.3, 0.3},
      {-0.3, 0.3, -0.3},
      {0.3, -1.5, 0.3},
      {0.3, -1.5, -0.3},
      {-0.3, -1.5, 0.3},
      {-0.3, -1.5, -0.3},
  }};

  BlockData blockToPalce{};

private:
  void DoCrosshairRayCast();
  void DoMove(float deltaTime);
  void DoJump(float deltaTime);
  void DoRotateByKey(float deltaTime);
  void DoRotateByMouse(float deltaTime);
  void DoBlockInteraction(float deltaTime);
  void DoEscapeCheck();
  void DoDirectionCheck();

  Ref<World> m_world{nullptr};
  Ref<Persistence> m_persistence{nullptr};
  Ref<Camera> m_camera{nullptr};

  Direction m_direction;

  HitTarget m_hitTarget;
  bool m_hasHit = false;

  bool m_isUsingMouse = false;

  glm::vec3 m_gravity{0};
  bool m_canJump = false;
  bool m_isRunning = false;
  float m_autoJumpMaxHeight = 1.f;

  glm::vec3 m_velocity{0}; // 当前速度矢量
  float m_acceleration = 15.0f;
  float m_friction = 8.0f;
};